home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / UTILITIE / UNIX_COH / 2774A.ZIP / LLESH.CZ / LLESH
Text File  |  1991-07-02  |  16KB  |  602 lines

  1. /* Shell Extension Program for UNIX Bourne Shell                       
  2.  
  3.    Provides aliases, history, command editing, dir tree, & pathname prompt
  4.  
  5.    Author: Thad Unrein
  6.    Date:   Aug 10 1990
  7.    Source: /usr/thad/src/shsrc
  8.  
  9.    Description: 
  10.  
  11.    Program produces a prompt, takes a string as a command line, parses
  12.    it for special tokens with strtok, then after taking action on any
  13.    special tokens it finds, resubmits the entire (ugh) string to 
  14.    system() for execution.  Of course the problem with this approach  
  15.    is that even though the special actions provided are executed, when  
  16.    they are resubmitted via system(), you get an error message; very ugly
  17.    but it works. (I have suggested some equally ugly solutions).
  18.  
  19.    Parsed commands:
  20.  
  21.    q == quit to top level shell
  22.  
  23.    cd == change directory
  24.  
  25.    lh == list history
  26.  
  27.    prev [n] == repeat n commandline from history.
  28.            With no arg repeats most recent.
  29.  
  30.    fc [n] == edit n commandline from history.  Edits most recent with no arg.
  31.  
  32.    alias [foo=bar] Establish alias. With no arg lists aliases.
  33.    
  34.    eg alias frog='cd /usr' - frog will now change to directory /usr.
  35.  
  36. Revision History:
  37.  
  38.    08/20/90 - added logic to allow commands after listing page of history (lh)
  39.  
  40.               c == continue
  41.               q == quit
  42.               <n> == command number to re-execute
  43.               <CR> == continue
  44.  
  45.    08/25/90 - added 'dt' command to list directory path names and change
  46.               to a numbered pathname - action and commands same as above
  47.               for 'lh' except that <n> cd's instead of re-executes.  
  48.  
  49.    09/01/90 - added numeric arg to lh
  50.               now if you type lh <n> where <n> is a number, lh will
  51.               begin listing history with that command line.
  52.  
  53.    09/06/90 - changed 'r' command to 'prev' to avoid erroneous parsing
  54.               with commands that have 'r' options.
  55.  
  56. Bugs:
  57.  
  58.    You must manually create .histfile and .aliasfile in your HOME directory
  59.    cat > .histfile
  60.             ^D
  61.  
  62.    will do it (same for .aliasfile)
  63.  
  64.    I realize that having the program create the files if it doesn't find
  65.    them is easy enough, but frankly I'm tired of working on this thing.
  66.  
  67.    Eventually I'll find elegant :-} solutions for these.
  68.  
  69.    Errant error messages:
  70.  
  71.    1. cd'ing to any directory where the arg
  72.       is not . , .. , or a full pathname. (Bad directory)
  73.    
  74.    If this error message gets on your nerves (it did mine) define
  75.    NOBDERR at compile.  This rewrites the command line to include a 
  76.    full pathname for cd, but also precludes using cd in a compound
  77.    command string e.g. cd usr;lc. 
  78.    
  79.    2. lh, dt - can't find
  80.  
  81.    To solve these (and compound the ugliness) I put dummy executables
  82.    for lh and dt in my /usr/local/bin (which is where 'shell' is).
  83.  
  84.    Since the command line is completely parsed before being submitted
  85.    to system(), built in commands (lh, cd, dt, prev, etc) will be executed
  86.    before standard UNIX commands.  Therefore the command line:
  87.  
  88.    lc;lh;cd /usr
  89.  
  90.    will be executed as:
  91.  
  92.    lh;cd /usr;lc
  93.    
  94.    Also, since everything is executed in a sub-shell via system, setting
  95.    variables (eg frog=hop) from the prompt won't work, since they dissap-
  96.    pear as soon as system returns.
  97.    
  98.    For the same reason 'cd' has to be implemented as a system call in the
  99.    code; otherwise you just change directories for the subshell.
  100.  
  101.  
  102. */
  103.  
  104.  
  105.  
  106. #include <stdio.h>
  107. #include <string.h>
  108. #include <ctype.h>
  109. #include <sys/types.h>
  110. #include <sys/dir.h>
  111. #include <sys/stat.h>
  112.  
  113. #define BUFFER 256
  114. #define TRUE    1
  115. #define FALSE   0
  116.  
  117. struct Alias {
  118.     char Name[9];
  119.     char Line[81];
  120. };
  121.  
  122. struct Alias *SavAlias[128];
  123.  
  124. char *DirStr[500];    /* Room for 500 pointers to directory strings */
  125. char String[81];
  126. char CmdLine[81]; 
  127. char *CmdHist[128];    /* Limit history to previous 128 commands */
  128. char *HistFilNam =  "/.histfile"; 
  129. char *AliasFilNam = "/.aliasfile"; 
  130. char PathName[81];   /* Pathname for .histfile */
  131. char APathName[81];  /* Pathname for .aliasfile */
  132. char PromptName[81]; /* Stores PS1 to use as lead string for prompt so you
  133.                         know if you are $ or root
  134.                      */ 
  135. char EditFileName[17];
  136. char HOMEBuf[BUFFER];
  137. char CD[81];
  138.  
  139. FILE *HistFil; 
  140. FILE *AliasFil; 
  141. FILE *EditFile;
  142.  
  143. char *malloc();
  144.  
  145. int CmdCount, AliasCount = 1, i = 0;
  146. int DirCount = 0, Page;
  147. int ChDir;
  148.                        /* Flags */
  149. int RepeatFlag = 0;
  150.  
  151. FILE *ReadF(FilNam)
  152. char *FilNam;
  153. {
  154.    FILE *RF;
  155.    if((RF = fopen(FilNam, "r")) == NULL)
  156.    {
  157.       fprintf(stderr,"\nUnable to open %s for reading\n", FilNam);
  158.       exit(-1);
  159.    }
  160. return(RF);
  161. }
  162.  
  163. FILE *WriteF(FilNam)
  164. char *FilNam;
  165. {
  166.    FILE *WF;
  167.    if((WF = fopen(FilNam, "w")) == NULL)
  168.    {
  169.       fprintf(stderr,"\nUnable to open %s for writing\n", FilNam );
  170.       exit(-1);
  171.    }
  172. return(WF);
  173. }
  174.  
  175. GetDir(PathN)
  176. char *PathN;
  177. {
  178.    struct stat DirBuf;
  179.    
  180.    if(stat(PathN, &DirBuf) == -1)
  181.    {
  182.       fprintf(stderr, "Can't access %s\n", PathN);
  183.       return;
  184.    }
  185.    if((DirBuf.st_mode & S_IFMT) == S_IFDIR)
  186.    {
  187.       ListDir(PathN);
  188.       ++DirCount;
  189.       DirStr[DirCount] = malloc((sizeof(String)) + 1);
  190.       strcpy(DirStr[DirCount], PathN);
  191.    }
  192. }
  193.  
  194. ListDir(PathN)
  195. char *PathN;
  196. {
  197.    struct direct DPath;
  198.    char *PathLen, *PN;
  199.    int i, FilD;
  200.  
  201.    PathLen = PathN + strlen(PathN);
  202.    *PathLen++ = '/';
  203.    if(PathLen + DIRSIZ + 2 >= PathN + BUFSIZ)
  204.       return;
  205.    if((FilD = open(PathN, 0)) == -1)
  206.       return;
  207.    while(read(FilD, (char *)&DPath, sizeof(DPath)) > 0)
  208.    {
  209.       if(DPath.d_ino == 0)
  210.          continue;
  211.       if(strcmp(DPath.d_name, ".") == 0)
  212.          continue;
  213.       if(strcmp(DPath.d_name, "..") == 0)
  214.          continue;
  215.       PN = PathLen; 
  216.       for(i = 0; i < DIRSIZ; i++)
  217.          *PN++ = DPath.d_name[i];
  218.       *PN++ = '\0';
  219.       GetDir(PathN);
  220.    }
  221.    close(FilD);
  222.    *--PathLen = '\0';
  223. }
  224.  
  225. void Parse()
  226. {
  227.    char *CmdPtr, separators[5] = " =;\n", Choice[4];
  228.    int ChCmd;
  229.  
  230.    CmdPtr = strtok(CmdLine, separators);
  231.    while(CmdPtr != NULL)
  232.    {
  233. #ifdef DEBUG   
  234.       printf("Top of loop, CmdPtr = %s\n", CmdPtr);
  235. #endif
  236.       if(strcmp(CmdPtr, "q") == 0)
  237.       { 
  238. #ifdef DEBUG 
  239.      printf("In q, CmdPtr = %s\n", CmdPtr);
  240. #endif
  241.          HistFil = WriteF(PathName); 
  242. #ifdef DEBUG
  243.          printf("PathName = %s\n", PathName);
  244. #endif
  245.          for(i = 1; i <= CmdCount; ++i) 
  246.          {
  247.             fputs(CmdHist[i], HistFil); 
  248.          }
  249.  
  250.          AliasFil = WriteF(APathName); 
  251.  
  252.          for(i = 1; i < AliasCount; ++i)
  253.          {
  254.             fputs(SavAlias[i] -> Name, AliasFil); 
  255.             fputs(SavAlias[i] -> Line, AliasFil); 
  256.          }
  257.          exit(0);
  258.       }
  259.                        /* cd for CURRENT process */
  260.  
  261.       else if(strcmp(CmdPtr, "cd") == 0)
  262.       {
  263.          CmdPtr = strtok(NULL, separators);        
  264.          if(! CmdPtr)
  265.             chdir(getenv("HOME"));
  266. #ifdef NOBDERR
  267.          else if(strncmp(CmdPtr, "/", 1) != 0)
  268.          {
  269.             strcpy(HOMEBuf, getwd());
  270.             strcat(HOMEBuf, "/");
  271.             strcat(HOMEBuf, CmdPtr);
  272.             chdir(HOMEBuf);
  273.             strcat(HOMEBuf, "\n");
  274.             strcpy(CD, "cd "); 
  275.             strcat(CD, HOMEBuf);
  276.             CmdHist[CmdCount] = malloc(sizeof(CD) + 1);
  277.             strcpy(CmdHist[CmdCount], CD);
  278.             HOMEBuf[0] = '\0';
  279.             CD[0] = '\0';
  280.             return;
  281.          }
  282.          else
  283. #endif
  284.             chdir(CmdPtr);
  285.       }
  286.       else if(strcmp(CmdPtr, "dt") == 0)
  287.       {
  288.  
  289.          CmdPtr = strtok(NULL, separators);        
  290.          if(CmdPtr == NULL)
  291.          {
  292.             strcpy(HOMEBuf, getwd());
  293.             CmdPtr = malloc(sizeof(HOMEBuf) + 1);
  294.             strcpy(CmdPtr, HOMEBuf);
  295.          } 
  296.          printf("Loading Pathnames\n"); 
  297.          GetDir(CmdPtr);
  298.        
  299.          i = 1;
  300.          while(i <= DirCount) 
  301.          {
  302.             printf("%d\t%s\n",i, DirStr[i]);
  303.             if(i == DirCount || (i % 23) == 0)
  304.             {
  305.                start:           
  306.                fflush(stdin);
  307.                printf(": ");
  308.                gets(Choice);
  309.                switch(Choice[0])
  310.                {
  311.                   case 'c':break;
  312.                   case 'q':goto finish;
  313.                   case '?':
  314.                      printf("c)ontinue, q)uit, <Dir Number> to chdir");
  315.                      goto start;
  316.                   default:
  317.                      if((isdigit(Choice[0])) != 0)
  318.                      {
  319.                         ChDir = atoi(Choice);
  320.                        /* DirStr[DirCount] = malloc(strlen(DirStr[ChDir]) + 1);
  321.                         strcpy(DirStr[DirCount], DirStr[ChDir]);
  322.                        */
  323.                         if((chdir(DirStr[ChDir])) != 0)
  324.                fprintf(stderr, "Can't change to that %s\n", DirStr[ChDir]);
  325.                         goto finish; 
  326.                      }
  327.                      else
  328.                      break;
  329.                 } 
  330.             } 
  331.             ++i; 
  332.       }
  333.       finish:;
  334.       DirCount = 0;
  335.    }
  336.                /* lh lists history of commands stored in CmdHist */
  337.                /* a screenfull at a time                         */
  338.  
  339.       else if(strcmp(CmdPtr, "lh") == 0)
  340.       {
  341. /* check for a numeric argument to lh; begin listing with that command string */
  342. /* from history list */         
  343.                 /* get next token */
  344.  
  345.          CmdPtr = strtok(NULL, separators);
  346.  
  347.                 /* is next token a numeral? */
  348.  
  349.          if((i = atoi(CmdPtr)) != 0)
  350.             ; 
  351.          else
  352.             i = 1;
  353.           
  354.            while(i <= CmdCount) 
  355.            {
  356.               printf("%d\t%s",i, CmdHist[i]);
  357.               if(i == CmdCount || (i % 23) == 0)
  358.               {
  359.                  Page = 0;
  360.                  begin:
  361.                  fflush(stdin);
  362.                  printf(": ");
  363.                  gets(Choice);
  364.                  switch(Choice[0])
  365.                  {
  366.                     case 'c':break;
  367.                     case 'q':
  368.                       goto end; 
  369.                     case '?':
  370.                       printf("c)ontinue, q)uit, <Cmd Number> to re-execute");
  371.                       goto begin;
  372.                     default:
  373.                       if((isdigit(Choice[0])) != 0)
  374.                       {
  375.                          ChCmd = atoi(Choice);
  376.                          CmdHist[CmdCount] = malloc(strlen(CmdHist[ChCmd]) + 1);
  377.                          strcpy(CmdHist[CmdCount], CmdHist[ChCmd]);
  378.                          RepeatFlag = 1;
  379.                          goto end; 
  380.                       }
  381.                       else
  382.                       break;
  383.                  } 
  384.               } 
  385.               ++i; 
  386.            }
  387.        end:;
  388.        }
  389.  
  390.        /* Let's go for broke - Aliases!! */
  391.  
  392.       else if(strcmp(CmdPtr, "alias") == 0)
  393.       {
  394. #ifdef DEBUG
  395.          printf("in alias, CmdPtr = %s\n", CmdPtr);
  396. #endif
  397.          CmdPtr = strtok(NULL, separators);         /*    advance CmdPtr    */ 
  398.          if(! CmdPtr)                               /*   no args to alias   */
  399.             for(i = 1; i < AliasCount;  ++i)        /* list current aliases */
  400.  
  401.                printf("%s\t%s", SavAlias[i] -> Name, SavAlias[i] -> Line);
  402.          else                     
  403.          {                                          /*    establish alias   */
  404.             SavAlias[AliasCount] = malloc(sizeof(struct Alias));
  405. #ifdef DEBUG
  406.             printf("Before Name, CmdPtr = %s\n", CmdPtr);
  407. #endif
  408.         strcpy(SavAlias[AliasCount] -> Name, CmdPtr); 
  409.         strcat(SavAlias[AliasCount] -> Name, "\n"); 
  410.         CmdPtr = strtok(NULL, "\'\"");
  411. #ifdef DEBUG
  412.             printf("Before Line, CmdPtr = %s\n", CmdPtr);
  413. #endif
  414.             strcpy(SavAlias[AliasCount] -> Line, CmdPtr);
  415.             strcat(SavAlias[AliasCount] -> Line, "\n");
  416.             CmdPtr = strtok(NULL, separators);
  417.             ++AliasCount;
  418.          }
  419.       }
  420.       else if(strcmp(CmdPtr, "prev") == 0)
  421.       {
  422.          i = 0;
  423.  
  424. #ifdef DEBUG
  425.    printf("in r, CmdPtr = %s\n", CmdPtr);
  426. #endif
  427.  
  428. /* check for a numeric argument to prev and execute that command string */
  429. /* from history list */         
  430.  
  431.                 /* get next token */
  432.  
  433.          CmdPtr = strtok(NULL, separators);
  434.  
  435.                 /* is next token a numeral? */
  436.  
  437.          if((i = atoi(CmdPtr)) != 0)
  438.          {
  439.             CmdHist[CmdCount] = malloc(strlen(CmdHist[i]) + 1);
  440.             strcpy(CmdHist[CmdCount], CmdHist[i]);
  441.          }
  442.  
  443.                  /* if no argument execute previous command */
  444.  
  445.          else
  446.          {
  447.             CmdHist[CmdCount] = malloc(strlen(CmdHist[CmdCount - 1]) + 1);
  448.             strcpy(CmdHist[CmdCount], CmdHist[CmdCount - 1]);
  449.          }    
  450.  
  451.          RepeatFlag = 1;
  452.       }
  453.       else if(strcmp(CmdPtr, "fc") == 0)
  454.       {
  455.  
  456. /* check for a numeric argument to fc and edit that command string */
  457. /* from history list */         
  458.  
  459.          i = 0;
  460.  
  461.          CmdPtr = strtok(NULL, separators);
  462.  
  463.                 /* is next token a numeral? */
  464.         
  465.          strcpy(EditFileName, mktemp("/tmp/shellXXXXXX")); 
  466.          EditFile = WriteF(EditFileName);
  467.          
  468.          if((i = atoi(CmdPtr)) != 0)
  469.          {
  470.             fputs(CmdHist[i], EditFile);
  471.             fclose(EditFile);
  472.             if(fork() == 0)
  473.                execl("/bin/vi","vi",EditFileName, (char *) 0);
  474.             else
  475.                wait((int *) 0);
  476.                CmdHist[CmdCount] = malloc(81);
  477.                EditFile = ReadF(EditFileName);
  478.                fgets(CmdHist[CmdCount], 81, EditFile);
  479.                fclose(EditFile);
  480.          }
  481.  
  482.                  /* if no argument edit previous command */
  483.  
  484.          else
  485.          {
  486.             fputs(CmdHist[CmdCount - 1], EditFile);
  487.             fclose(EditFile);
  488.             if(fork() == 0)
  489.                execl("/bin/vi","vi",EditFileName, (char *) 0);
  490.             else
  491.                wait((int *) 0);
  492.                CmdHist[CmdCount] = malloc(81);
  493.                EditFile = ReadF(EditFileName);
  494.                fgets(CmdHist[CmdCount], 81, EditFile);
  495.                fclose(EditFile);
  496.          }  
  497.  
  498.          if(unlink(EditFileName) != 0)
  499.             fprintf(stderr, "Can't unlink %s\n", EditFileName);
  500.      
  501.          RepeatFlag = 1;
  502.       }
  503.                 /* get next token */
  504.    
  505.    CmdPtr = strtok(NULL, separators);        
  506. #ifdef DEBUG
  507.    printf("Bottom of loop, CmdPtr = %s\n", CmdPtr);
  508.    printf("Bottom of loop, CmdLine = %s\n", CmdLine);
  509.    
  510. #endif
  511.    }            
  512. }
  513.  
  514. main()
  515. {
  516.    char CmdString[81];
  517.    CmdCount = 0;
  518.  
  519.                              /* open history file */
  520.  
  521. strcpy(PathName, getenv("HOME"));
  522. strcpy(APathName, getenv("HOME"));
  523.  
  524.   
  525. strcat(PathName, HistFilNam);
  526.  
  527. #ifdef DEBUG
  528.   printf("PathName for HistFile = %s\n", PathName);
  529. #endif
  530.  
  531.   HistFil = ReadF(PathName);
  532.  
  533.   while(fgets(CmdString, 81, HistFil) != NULL)
  534.   {
  535.      ++CmdCount;
  536.      CmdHist[CmdCount] = malloc(strlen(CmdString) + 1);
  537.      strcpy(CmdHist[CmdCount], CmdString); 
  538.   }
  539.   fclose(HistFil);
  540.  
  541.   strcat(APathName, AliasFilNam);
  542.  
  543.   AliasFil = ReadF(APathName);
  544.  
  545.   while(fgets(CmdString, 9, AliasFil) != NULL)
  546.   {
  547.      SavAlias[AliasCount] = malloc(sizeof(struct Alias));
  548.      strcpy(SavAlias[AliasCount] -> Name, CmdString); 
  549.      fgets(CmdString, 81, AliasFil);
  550.      strcpy(SavAlias[AliasCount] -> Line, CmdString); 
  551.      ++AliasCount;
  552.   }
  553.   fclose(AliasFil);
  554.  
  555.    while(1)
  556.    {
  557.       char directory[80];
  558.    
  559.       strcpy(directory, getwd());
  560.       strcpy(PromptName, getenv("PS1"));
  561.  
  562.       printf("%s%s [%d]>", PromptName, directory, CmdCount);
  563.  
  564.       fgets(CmdLine, 81, stdin);
  565.  
  566.       if(strcmp(CmdLine,"\n") != 0)
  567.       
  568.       {
  569.          for(i = 1; i < AliasCount; ++i)
  570.             if(strncmp(CmdLine, SavAlias[i] -> Name, strlen(CmdLine)) == 0)
  571.             strcpy(CmdLine, SavAlias[i] -> Line); 
  572.          ++CmdCount;
  573.       }
  574.  
  575.       if(CmdCount > 128) 
  576.         CmdCount = 1;
  577.  
  578.       CmdHist[CmdCount] = malloc(strlen(CmdLine) + 1);
  579.       
  580.       strcpy(CmdHist[CmdCount], CmdLine);    /* copy for history */
  581.  
  582.       Parse();
  583.  
  584.       if(RepeatFlag)
  585.       {
  586.          RepeatFlag = 0;
  587.          strcpy(CmdLine, CmdHist[CmdCount]);
  588.          printf("%s\n", CmdLine);
  589.          Parse();
  590.          strcpy(CmdLine, CmdHist[CmdCount]);
  591.       }
  592.       else
  593.         strcpy(CmdLine, CmdHist[CmdCount]);    /* get unaltered CmdLine */
  594. #ifdef DEBUG   
  595.       printf("At system - CmdHist[CmdCount] = %s\n", CmdHist[CmdCount]);
  596. #endif
  597.         system(CmdLine);
  598.  
  599.    }
  600. }   
  601.  
  602.